package fr.bludwarf.skywarrior.global;

import java.util.HashMap;

import fr.bludwarf.skywarrior.evenements.Evenement;
import fr.bludwarf.skywarrior.exceptions.ConstructionImpossible;
import fr.bludwarf.skywarrior.exceptions.EvenementInconnuOublie;
import fr.bludwarf.skywarrior.exceptions.IleInconnue;
import fr.bludwarf.skywarrior.exceptions.JoueurInconnu;
import fr.bludwarf.skywarrior.ile.TypeBatiment;
import fr.bludwarf.skywarrior.ile.EtatIle;
import fr.bludwarf.skywarrior.ile.Ile;
import fr.bludwarf.skywarrior.joueur.EtatJoueur;
import fr.bludwarf.skywarrior.joueur.Joueur;
import fr.bludwarf.skywarrior.joueur.Techno;

public class EtatMonde extends EtatPere<Monde, Joueur, EtatJoueur> {
	
	private Temps _temps;

	// FIXME : pour le debug
	/**
	 * Crée un nouveau monde à l'instant 0
	 * @param debut date et heure réelles du début de la partie
	 */
	public EtatMonde(final Monde monde, final Temps temps) {
		super(monde, null);
		_temps = temps;
		super.init();
	}
	
	/**
	 * Constructeur de recopie
	 * @param etat état de base
	 * @throws Exception 
	 */
	public EtatMonde(final EtatMonde etat) throws Exception {
		super(etat);
		_temps = etat._temps;
	}
	
	public Monde getMonde() {
		return _entite;
	}
	
	@Override
	public String toString() {
		final StringBuilder sb = new StringBuilder();
		final double tCycle = prochainCycle().tempsRestant();

		sb.append("===== MONDE le " + getTemps().formatDateReelle() + " (t = ")
			.append(getTemps()).append(") === Prochain cycle : " + Temps.toString(tCycle) + " =====");
		
		for (final EtatJoueur etat : _etatsFils.values())
		{
			sb.append("\n").append(etat);
		}

		return sb.toString();
	}

	/**
	 * @return
	 * @since 17 nov. 2011
	 */
	public Evenement prochainCycle() {
		return getTemps().prochainCycle(this);
	}

	public HashMap<Joueur, EtatJoueur> getEtatsJoueurs() {
		return _etatsFils;
	}
	
	public EtatJoueur getEtatJoueur(final String nomJoueur) throws JoueurInconnu
	{
		return getEtatJoueur(_entite.getJoueur(nomJoueur));
	}

	public EtatJoueur getEtatJoueur(Joueur joueur) {
		return _etatsFils.get(joueur);
	}

	@Override
	public Evenement prochainEvenement() {
		return Evenement.prochainEvenementParmis(
				prochainCycle(), // prochain cycle
				Evenement.prochainEvenementDe(_etatsFils.values()) // prochain évènement parmis tous les joueurs
		);
	}

	@Override
	protected EtatJoueur etatInitialFils(final Joueur joueur) {
		return new EtatJoueur(joueur, this);
	}

	public EtatIle getEtatIle(Ile ile) throws IleInconnue {
		// Parcours des joueurs
		for (final Joueur joueur : getEtatsJoueurs().keySet())
		{
			final EtatJoueur etatJoueur = getEtatsJoueurs().get(joueur);
			if (etatJoueur.getEtatsIles().containsKey(ile))
			{
				return etatJoueur.getEtatsIles().get(ile);
			}
		}
		throw new IleInconnue(ile.getNom());
	}
	
	

	/************************************************************************
	 *                         ETAT INITIAL DU MONDE
	 ************************************************************************/
	
	/**
	 * Ajoute un certain nombre de bâtiment sur une ile
	 * @param nb
	 * @param batiment
	 * @param ile
	 * @throws IleInconnue 
	 */
	public void addBatiment(final int nb, final TypeBatiment batiment, final Ile ile) throws IleInconnue
	{
		final EtatIle etatIle = getEtatIle(ile);
		for (int i = 0; i < nb; ++i) {
			etatIle.add(batiment);
		}
	}
	
	/**
	 * Quantité de matériaux et d'éther en stock d'un joueur
	 * @param materiaux
	 * @param ether
	 * @param joueur
	 */
	public void setStocks(final int materiaux, final int ether, final Joueur joueur)
	{
		getEtatJoueur(joueur).setStocks(materiaux, ether);
	}
	
	/**
	 * Ajoute une construction dans la liste des constructions d'une ile
	 * @param tempsRestant
	 * @param batiment
	 * @param ile
	 * @param commencee cette construction a commencée
	 */
	public void addConstruction(final double tempsRestant, final TypeBatiment batiment, final Ile ile, final boolean commencee)
	{
		// TODO Auto-generated constructor stub
	}
	
	/**
	 * Ajoute une techno à un joueur
	 * @param techno
	 * @param joueur
	 */
	public void addTechno(final Techno techno, final Joueur joueur)
	{
		// TODO Auto-generated constructor stub
	}
	
	/**
	 * Ajoute une techno dans la liste des recherche d'un joueur
	 * @param tempsRestant
	 * @param techno
	 * @param joueur
	 */
	public void addRecherche(final double tempsRestant, final Techno techno, final Joueur joueur)
	{
		// TODO Auto-generated constructor stub
	}

	@Override
	protected EtatJoueur newEtatFils(EtatJoueur etatInitial) throws Exception {
		return new EtatJoueur(etatInitial);
	}
	
	@Override
	public void avancer(double temps) throws ConstructionImpossible, EvenementInconnuOublie {
		_temps = new Temps(_temps, temps);
		super.avancer(temps);
	}

	public void setEvenementDeclencheur(Evenement evenement) {
		_periode = new Periode(evenement.tempsRestant(), evenement, this);
	}
	
	@Override
	public Temps getTemps() {
		return _temps;
	}

	public boolean estUneIleVierge(Ile ile) {
		// Une ile est vierge, si elle n'apparait dans aucun état joueur
		try
		{
			getEtatIle(ile);
			return false;
		}
		catch (final IleInconnue e)
		{
			return true;
		}
	}
}
